"""
文件上传和检测路由模块
处理图像和视频文件的上传、检测和分析功能
"""
import os
import uuid
import json
from datetime import datetime
from flask import Blueprint, request, jsonify, current_app
from werkzeug.utils import secure_filename
from PIL import Image
import numpy as np
import cv2

from api.services.detection_service import DetectionService
from api.utils.response_utils import success_response, error_response
from api.utils.file_utils import allowed_file, get_file_size, generate_unique_filename
from api.middleware.auth_middleware import token_required
from api.middleware.rate_limit_middleware import rate_limit

# 创建蓝图
upload_bp = Blueprint('upload', __name__)

# 初始化检测服务
detection_service = DetectionService()

# 允许的图像文件扩展名
ALLOWED_IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
# 允许的视频文件扩展名
ALLOWED_VIDEO_EXTENSIONS = {'mp4', 'avi', 'mov', 'wmv'}
# 最大文件大小 (100MB)
MAX_FILE_SIZE = 100 * 1024 * 1024

# 上传目录配置
UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'uploads')
IMAGE_UPLOAD_FOLDER = os.path.join(UPLOAD_FOLDER, 'images')
VIDEO_UPLOAD_FOLDER = os.path.join(UPLOAD_FOLDER, 'videos')
RESULT_FOLDER = os.path.join(UPLOAD_FOLDER, 'results')

# 确保上传目录存在
for folder in [UPLOAD_FOLDER, IMAGE_UPLOAD_FOLDER, VIDEO_UPLOAD_FOLDER, RESULT_FOLDER]:
    os.makedirs(folder, exist_ok=True)

@upload_bp.route('/image', methods=['POST'])
@token_required
@rate_limit(limit=10, per=60)
def upload_image():
    """
    上传图像并进行目标检测
    支持单张图像上传，返回检测结果和可视化后的图像
    """
    try:
        # 检查是否有文件
        if 'file' not in request.files:
            return error_response('No file part', 400)
        
        file = request.files['file']
        
        # 检查文件是否为空
        if file.filename == '':
            return error_response('No selected file', 400)
        
        # 检查文件类型
        if not allowed_file(file.filename, ALLOWED_IMAGE_EXTENSIONS):
            return error_response('Invalid file type. Allowed types: png, jpg, jpeg, gif', 400)
        
        # 检查文件大小
        file.seek(0, os.SEEK_END)
        file_size = file.tell()
        file.seek(0)
        
        if file_size > MAX_FILE_SIZE:
            return error_response(f'File too large. Maximum size: {MAX_FILE_SIZE / 1024 / 1024}MB', 400)
        
        # 获取检测参数
        detection_mode = request.form.get('detection_mode', 'standard')
        confidence_threshold = float(request.form.get('confidence_threshold', 0.5))
        enable_helmet_detection = request.form.get('enable_helmet_detection', 'true').lower() == 'true'
        
        # 生成唯一文件名
        filename = generate_unique_filename(file.filename)
        filepath = os.path.join(IMAGE_UPLOAD_FOLDER, filename)
        
        # 保存文件
        file.save(filepath)
        
        # 加载图像
        image = Image.open(filepath)
        image_np = np.array(image)
        
        # 执行检测
        detection_results = detection_service.detect_objects(
            image_np,
            confidence_threshold=confidence_threshold,
            enable_helmet_detection=enable_helmet_detection,
            detection_mode=detection_mode
        )
        
        # 生成可视化结果
        result_filename = f"result_{filename}"
        result_filepath = os.path.join(RESULT_FOLDER, result_filename)
        
        # 可视化检测结果
        visualized_image = detection_service.visualize_detections(image_np, detection_results)
        cv2.imwrite(result_filepath, cv2.cvtColor(visualized_image, cv2.COLOR_RGB2BGR))
        
        # 生成检测报告
        detection_report = generate_detection_report(detection_results, 'image', filename)
        
        # 保存检测历史
        save_detection_history(detection_report)
        
        # 返回结果
        return success_response({
            'filename': filename,
            'file_size': file_size,
            'detection_count': len(detection_results['detections']),
            'detections': detection_results['detections'],
            'statistics': detection_results['statistics'],
            'result_image_url': f'/uploads/results/{result_filename}',
            'processing_time': detection_results['processing_time'],
            'timestamp': detection_report['timestamp']
        })
        
    except Exception as e:
        current_app.logger.error(f"Error processing image: {str(e)}")
        return error_response(f'Error processing image: {str(e)}', 500)

@upload_bp.route('/video', methods=['POST'])
@token_required
@rate_limit(limit=5, per=300)  # 限制视频上传频率
def upload_video():
    """
    上传视频并进行目标检测
    支持短视频文件分析，返回检测结果统计
    """
    try:
        # 检查是否有文件
        if 'file' not in request.files:
            return error_response('No file part', 400)
        
        file = request.files['file']
        
        # 检查文件是否为空
        if file.filename == '':
            return error_response('No selected file', 400)
        
        # 检查文件类型
        if not allowed_file(file.filename, ALLOWED_VIDEO_EXTENSIONS):
            return error_response('Invalid file type. Allowed types: mp4, avi, mov, wmv', 400)
        
        # 检查文件大小
        file.seek(0, os.SEEK_END)
        file_size = file.tell()
        file.seek(0)
        
        if file_size > MAX_FILE_SIZE * 2:  # 视频文件允许更大的大小
            return error_response(f'File too large. Maximum size: {MAX_FILE_SIZE * 2 / 1024 / 1024}MB', 400)
        
        # 获取检测参数
        detection_mode = request.form.get('detection_mode', 'standard')
        confidence_threshold = float(request.form.get('confidence_threshold', 0.5))
        enable_helmet_detection = request.form.get('enable_helmet_detection', 'true').lower() == 'true'
        frame_interval = int(request.form.get('frame_interval', 10))  # 每N帧检测一次
        
        # 生成唯一文件名
        filename = generate_unique_filename(file.filename)
        filepath = os.path.join(VIDEO_UPLOAD_FOLDER, filename)
        
        # 保存文件
        file.save(filepath)
        
        # 视频分析
        analysis_results = analyze_video(
            filepath,
            confidence_threshold,
            enable_helmet_detection,
            detection_mode,
            frame_interval
        )
        
        # 生成分析报告
        video_report = generate_detection_report(
            analysis_results,
            'video',
            filename,
            video_info={
                'duration': analysis_results['duration'],
                'frame_count': analysis_results['frame_count'],
                'fps': analysis_results['fps']
            }
        )
        
        # 保存检测历史
        save_detection_history(video_report)
        
        # 返回结果
        return success_response({
            'filename': filename,
            'file_size': file_size,
            'video_info': {
                'duration': analysis_results['duration'],
                'frame_count': analysis_results['frame_count'],
                'fps': analysis_results['fps']
            },
            'total_frames_processed': analysis_results['frames_processed'],
            'statistics': analysis_results['statistics'],
            'timeline_data': analysis_results['timeline_data'],
            'processing_time': analysis_results['processing_time'],
            'timestamp': video_report['timestamp']
        })
        
    except Exception as e:
        current_app.logger.error(f"Error processing video: {str(e)}")
        return error_response(f'Error processing video: {str(e)}', 500)

@upload_bp.route('/batch', methods=['POST'])
@token_required
@rate_limit(limit=3, per=120)
def batch_upload():
    """
    批量上传图像进行检测
    """
    try:
        # 检查是否有文件
        if 'files' not in request.files:
            return error_response('No files part', 400)
        
        files = request.files.getlist('files')
        
        if len(files) == 0:
            return error_response('No files selected', 400)
        
        if len(files) > 10:  # 限制批量上传数量
            return error_response('Too many files. Maximum 10 files allowed', 400)
        
        # 获取检测参数
        confidence_threshold = float(request.form.get('confidence_threshold', 0.5))
        enable_helmet_detection = request.form.get('enable_helmet_detection', 'true').lower() == 'true'
        
        results = []
        total_detections = 0
        overall_statistics = {}
        
        # 处理每个文件
        for file in files:
            if file.filename == '':
                continue
            
            if not allowed_file(file.filename, ALLOWED_IMAGE_EXTENSIONS):
                continue
            
            # 生成唯一文件名
            filename = generate_unique_filename(file.filename)
            filepath = os.path.join(IMAGE_UPLOAD_FOLDER, filename)
            
            # 保存文件
            file.save(filepath)
            
            # 加载图像
            image = Image.open(filepath)
            image_np = np.array(image)
            
            # 执行检测
            detection_results = detection_service.detect_objects(
                image_np,
                confidence_threshold=confidence_threshold,
                enable_helmet_detection=enable_helmet_detection
            )
            
            # 更新统计信息
            total_detections += len(detection_results['detections'])
            
            # 合并统计数据
            for cls, count in detection_results['statistics'].items():
                if cls not in overall_statistics:
                    overall_statistics[cls] = 0
                overall_statistics[cls] += count
            
            results.append({
                'filename': filename,
                'detection_count': len(detection_results['detections']),
                'statistics': detection_results['statistics'],
                'processing_time': detection_results['processing_time']
            })
        
        return success_response({
            'total_files': len(results),
            'total_detections': total_detections,
            'overall_statistics': overall_statistics,
            'results': results
        })
        
    except Exception as e:
        current_app.logger.error(f"Error processing batch upload: {str(e)}")
        return error_response(f'Error processing batch upload: {str(e)}', 500)

@upload_bp.route('/analyze-url', methods=['POST'])
@token_required
@rate_limit(limit=15, per=60)
def analyze_image_url():
    """
    分析网络图像URL
    """
    try:
        data = request.get_json()
        
        if not data or 'url' not in data:
            return error_response('Image URL is required', 400)
        
        image_url = data['url']
        confidence_threshold = float(data.get('confidence_threshold', 0.5))
        enable_helmet_detection = data.get('enable_helmet_detection', True)
        
        # 下载图像
        image_np = download_image_from_url(image_url)
        
        # 执行检测
        detection_results = detection_service.detect_objects(
            image_np,
            confidence_threshold=confidence_threshold,
            enable_helmet_detection=enable_helmet_detection
        )
        
        # 生成可视化结果
        filename = f"url_analysis_{uuid.uuid4().hex[:8]}.jpg"
        result_filepath = os.path.join(RESULT_FOLDER, filename)
        
        visualized_image = detection_service.visualize_detections(image_np, detection_results)
        cv2.imwrite(result_filepath, cv2.cvtColor(visualized_image, cv2.COLOR_RGB2BGR))
        
        return success_response({
            'image_url': image_url,
            'detection_count': len(detection_results['detections']),
            'detections': detection_results['detections'],
            'statistics': detection_results['statistics'],
            'result_image_url': f'/uploads/results/{filename}',
            'processing_time': detection_results['processing_time']
        })
        
    except Exception as e:
        current_app.logger.error(f"Error analyzing image URL: {str(e)}")
        return error_response(f'Error analyzing image URL: {str(e)}', 500)

# 辅助函数
def analyze_video(video_path, confidence_threshold, enable_helmet_detection, detection_mode, frame_interval):
    """分析视频文件并返回检测结果"""
    import time
    start_time = time.time()
    
    cap = cv2.VideoCapture(video_path)
    fps = cap.get(cv2.CAP_PROP_FPS)
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    duration = frame_count / fps if fps > 0 else 0
    
    frames_processed = 0
    frame_idx = 0
    
    # 累计统计
    overall_statistics = {}
    # 时间线数据（每秒的检测情况）
    timeline_data = []
    
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        
        # 每隔frame_interval帧检测一次
        if frame_idx % frame_interval == 0:
            # 转换为RGB
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            
            # 执行检测
            detection_results = detection_service.detect_objects(
                frame_rgb,
                confidence_threshold=confidence_threshold,
                enable_helmet_detection=enable_helmet_detection,
                detection_mode=detection_mode
            )
            
            # 更新统计
            frame_statistics = detection_results['statistics']
            
            # 合并到总体统计
            for cls, count in frame_statistics.items():
                if cls not in overall_statistics:
                    overall_statistics[cls] = 0
                overall_statistics[cls] += count
            
            # 记录时间线数据
            seconds = frame_idx / fps
            timeline_data.append({
                'timestamp': seconds,
                'frame_index': frame_idx,
                'detections': detection_results['detections'],
                'statistics': frame_statistics
            })
            
            frames_processed += 1
        
        frame_idx += 1
    
    cap.release()
    
    processing_time = time.time() - start_time
    
    return {
        'duration': round(duration, 2),
        'frame_count': frame_count,
        'fps': round(fps, 2),
        'frames_processed': frames_processed,
        'statistics': overall_statistics,
        'timeline_data': timeline_data,
        'processing_time': round(processing_time, 2)
    }

def generate_detection_report(detection_results, source_type, filename, video_info=None):
    """生成检测报告"""
    report = {
        'id': str(uuid.uuid4()),
        'timestamp': datetime.now().isoformat(),
        'source_type': source_type,
        'source_name': filename,
        'processing_time': detection_results.get('processing_time', 0),
        'statistics': detection_results.get('statistics', {})
    }
    
    if video_info:
        report['video_info'] = video_info
    
    return report

def save_detection_history(report):
    """保存检测历史记录"""
    # 在实际项目中，这里应该保存到数据库
    # 这里简单地打印日志
    current_app.logger.info(f"Detection history saved: {json.dumps(report, ensure_ascii=False)}")

def download_image_from_url(url):
    """从URL下载图像"""
    import requests
    from io import BytesIO
    
    response = requests.get(url, timeout=10)
    response.raise_for_status()
    
    image = Image.open(BytesIO(response.content))
    return np.array(image)

# 注册路由
def register_routes(app):
    """注册路由到Flask应用"""
    # 静态文件路由
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    
    # 注册蓝图
    app.register_blueprint(upload_bp, url_prefix='/api/upload')
    
    # 为上传文件提供静态访问
    from flask import send_from_directory
    
    @app.route('/uploads/<path:filename>')
    def uploaded_file(filename):
        return send_from_directory(UPLOAD_FOLDER, filename)

# 导出
__all__ = ['register_routes']